﻿﻿using System.Collections.Generic;
using System.Text;

namespace System.Web.Mvc
{
    /// <summary>
    /// Helper to inject css file includes, javascript file includes, inline css styles and inline javascript code from a view or partial view
    /// into a placeholder.
    /// The placeholder will mostly be located inside the &lt;head&gt; element or at the bottom inside the &lt;body&gt; element of the _Layout (master) page
    /// </summary>
    /// <remarks>
    /// Created by Christof Lauriers - It Pro Solutions
    /// This control was based on the AssetHelper control by Kalman Speier. More information about his AssetHelper can be found on the following page:
    /// https://github.com/speier/mvcassetshelper
    /// </remarks>
    public class AssetsHelper
    {
        private ItemRegistrar StyleSheetInclude { get; set; }
        private ItemRegistrar JavascriptInclude { get; set; }
        private ItemRegistrar InlineStyle { get; set; }
        private ItemRegistrar InlineJavascript { get; set; }

        public AssetsHelper()
        {
            StyleSheetInclude = new ItemRegistrar(ItemRegistrarFormatters.StylesheetIncludeFormat, AssetType.StylesheetInclude);
            JavascriptInclude = new ItemRegistrar(ItemRegistrarFormatters.JavascriptIncludeFormat, AssetType.JavascriptInclude);
            InlineStyle = new ItemRegistrar(ItemRegistrarFormatters.InlineStyleFormat, AssetType.InlineStyle);
            InlineJavascript = new ItemRegistrar(ItemRegistrarFormatters.InlineJavascriptFormat, AssetType.InlineJavascript);
        }

        public static AssetsHelper GetInstance(HtmlHelper htmlHelper)
        {
            const string instanceKey = "AssetsHelperInstance";

            var context = htmlHelper.ViewContext.HttpContext;
            if (context == null) return null;

            var assetsHelper = (AssetsHelper)context.Items[instanceKey];

            if (assetsHelper == null)
                context.Items.Add(instanceKey, assetsHelper = new AssetsHelper());

            return assetsHelper;
        }

        public void Add(string value, AssetType assetType)
        {
            switch (assetType)
            {
                case AssetType.StylesheetInclude:
                    StyleSheetInclude.Add(value);
                    break;
                case AssetType.JavascriptInclude:
                    JavascriptInclude.Add(value);
                    break;
                case AssetType.InlineStyle:
                    InlineStyle.Add(value);
                    break;
                case AssetType.InlineJavascript:
                    InlineJavascript.Add(value);
                    break;
            }
        }

        public IHtmlString Render(AssetType assetType)
        {
            IHtmlString htmlString = null;
            switch (assetType)
            {
                case AssetType.StylesheetInclude:
                    htmlString = StyleSheetInclude.Render();
                    break;
                case AssetType.JavascriptInclude:
                    htmlString = JavascriptInclude.Render();
                    break;
                case AssetType.InlineStyle:
                    htmlString = InlineStyle.Render();
                    break;
                case AssetType.InlineJavascript:
                    htmlString = InlineJavascript.Render();
                    break;
            }
            return htmlString;
        }
    }

    public class ItemRegistrar
    {
        private readonly string _format;
        private readonly IList<string> _items;
        private readonly AssetType _assetType;

        public ItemRegistrar(string format, AssetType assetType)
        {
            _format = format;
            _items = new List<string>();
            _assetType = assetType;
        }

        public ItemRegistrar Add(string value)
        {
            if (!_items.Contains(value))
                _items.Insert(0, value);

            return this;
        }

        public IHtmlString Render()
        {
            IHtmlString htmlString = null;
            switch (_assetType)
            {
                case AssetType.JavascriptInclude:
                case AssetType.StylesheetInclude:
                    var includeBuilder = new StringBuilder();
                    foreach (var item in _items)
                    {
                        var fmt = string.Format(_format, item);
                        includeBuilder.AppendLine(fmt);
                    }
                    htmlString = new HtmlString(includeBuilder.ToString());
                    break;

                case AssetType.InlineStyle:
                case AssetType.InlineJavascript:
                    var inlineBuilder = new StringBuilder();
                    foreach (var item in _items)
                    {
                        inlineBuilder.AppendLine(item);
                    }
                    htmlString = new HtmlString(string.Format(_format, inlineBuilder));
                    break;
            }
            return htmlString;
        }
    }

    public class ItemRegistrarFormatters
    {
        public const string StylesheetIncludeFormat = "<link href=\"{0}\" rel=\"stylesheet\" type=\"text/css\" />";
        public const string JavascriptIncludeFormat = "<script src=\"{0}\" type=\"text/javascript\"></script>";
        public const string InlineStyleFormat = "<style type=\"text/css\">{0}</style>";
        public const string InlineJavascriptFormat = "<script type=\"text/javascript\">{0}</script>";
    }

    public enum AssetType
    {
        StylesheetInclude,
        JavascriptInclude,
        InlineStyle,
        InlineJavascript
    }

    public static class HtmlHelperExtensions
    {
        public static AssetsHelper Assets(this HtmlHelper htmlHelper)
        {
            return AssetsHelper.GetInstance(htmlHelper);
        }
    }
}

